#include "ClusterAnalysis.h"

bool ClusterAnalysis::Init(vector<DataPoint>& inputDataSets, double radius, int minPTs)
{
	this->radius = radius;
	this->minPTs = minPTs;
	this->dimNum = DIME_NUM;
	this->dataSets = inputDataSets;
	this->dataNum=dataSets.size();
	this->kdTree = kd_create(DIME_NUM); 
	for(unsigned long i=0; i<dataNum;i++)
    {
		kd_insert(kdTree,dataSets[i].GetData(),&dataSets[i]);
    }
    for(unsigned long i=0; i<dataNum;i++)
    {
        SetNeighborPoints(dataSets[i]);
    }
	kd_free(kdTree);
    return true;
}

void ClusterAnalysis::SetNeighborPoints(DataPoint& dp)
{
	//use kdtree structure to compute the neighbourhood
	///*
	kdres* res = kd_nearest_range(kdTree, dp.GetData(), radius);
	int number_near = kd_res_size(res); 
    if (number_near >= minPTs) 
    { 
        dp.SetKey(true); 
		while (!kd_res_end(res)) 
            { 
                DataPoint* ptNear = (DataPoint*)kd_res_item(res,dp.GetData()); 
				dp.GetNeighborIds().push_back(ptNear->GetDpId()); 
                kd_res_next(res); 
            } 
    }else dp.SetKey(false);
    kd_res_free(res); //*/
}
 
bool ClusterAnalysis::DBSCANClustering()
{
	unsigned long clusterId=0;
    for(unsigned long i=0; i<dataNum;i++)
    {
        DataPoint& dp=dataSets[i];
        if(!dp.isVisited())
		{
			dp.SetVisited(true);
			if(dp.IsKey())
			{
				currentCluster.clear();
				dp.SetClusterId(clusterId);
				currentCluster.push_back(dp.GetDpId());
				KeyPointCluster(i,clusterId);		//expand clustering
				clusterId++;
				clusterPtsIds.push_back(currentCluster);
			}
		}
    }
	cout<<"cluster number "<<clusterPtsIds.size()<<endl;
	for(int i = 0;i<clusterPtsIds.size();i++) cout<<"cluster "<<i<<" has "<<clusterPtsIds[i].size()<<" points."<<endl;
    return true;
}

void ClusterAnalysis::KeyPointCluster(unsigned long dpID, unsigned long clusterId )
{
	///*
	DataPoint& srcDp = dataSets[dpID];        //get the data point
    vector<unsigned long> arrvalPoints = srcDp.GetNeighborIds();        //get the neighborhood IDs
	vector<unsigned long> neighbourhoods;
	for(unsigned long i=0; i<arrvalPoints.size(); i++)
	{
		DataPoint& desDp = dataSets[arrvalPoints[i]];
		if(!desDp.isVisited())
		{
			desDp.SetClusterId(clusterId);				//set clusterID
			currentCluster.push_back(desDp.GetDpId());  //add this piont ID to this cluster
            desDp.SetVisited(true);						//set it visited
			neighbourhoods.push_back(arrvalPoints[i]);
		}
	}

    for(unsigned long i=0; i<neighbourhoods.size(); i++)   //for every point in the NEIGHBORHOOD
    {
		DataPoint& desDp = dataSets[neighbourhoods[i]];    //a neighborhood data point
		if(desDp.IsKey())
        {
			vector<unsigned long>& arrvalPointsAdd = desDp.GetNeighborIds(); //the neighbor's neighborhood points
			for(int j=0;j<arrvalPointsAdd.size();j++)
			{
				DataPoint& nearDp = dataSets[arrvalPointsAdd[j]];
				if(!nearDp.isVisited())
				{
					 nearDp.SetVisited(true);
					 neighbourhoods.push_back(arrvalPointsAdd[j]);	//add neighbor's neighborhood to the NEIGHBORHOOD
				}
				if(nearDp.GetClusterId()==-1)
				{
					nearDp.SetClusterId(clusterId);					//set clusterID 
					currentCluster.push_back(nearDp.GetDpId());		//add this piont ID to this cluster
				}
			}
        }
	}//*/
	/* recursive solution
	DataPoint& srcDp = dataSets[dpID];        //get the data point
    if(!srcDp.IsKey())    return;
    vector<unsigned long>& arrvalPoints = srcDp.GetNeighborIds();        //get the neighborhood IDs
    for(unsigned long i=0; i<arrvalPoints.size(); i++)   //for every point in the neighborhood
    {
		DataPoint& desDp = dataSets[arrvalPoints[i]];    //neighborhood datapoint
        if(!desDp.isVisited())                           //if unvisited
        {
            desDp.SetClusterId(clusterId);        //set clusterID 
			currentCluster.push_back(desDp.GetDpId());  //add this piont ID to this cluster
            desDp.SetVisited(true);                //set it visited
            if(desDp.IsKey())
            {
                KeyPointCluster(desDp.GetDpId(),clusterId);    //do it recursively
            }
        }
    }//*/
}